/*! \file main.cpp
	\brief the file containing the main function, the call to the parser, and graph traversal code
	Adapted from examples by Terence Parr & Jim Idle    
*/

#include <laban.h>
#include <translate.cpp>
#include <check.h>
#include <iostream>

using namespace std;

//! DAG is a global variable that, essentially, holds a collection of edges.

/*! Each edge is in fact a pair of nodes, which in turn, are represented as a pair 
* whose first term is a string, (the node ID) and whose second term is an int
* (which is an auxiliary value that helps determine certain attributes of the node
*/
DAGedges DAG;

 //! This function is used to print information about an edge to a file output stream when traversing the graph.
    /*!
      \param parent a pair <string,int> representing the parent node of the edge 
      \param child  a pair <string,int> representing the child node of the edge
      \param first a flag set by the caller to indicate whether information about the parent should be printed
      \param fout the file output stream to which information will be sent.    
      
    */
void visit (DAGnode parent, DAGnode child, int first, ofstream &fout) {
	if (first)
		fout << endl << parent.first << " -> " << child.first;
	else
		fout << ", " << child.first;
}

//! This function is used to traverse the graph.
/*! \param strfname: a string that holds the name of the file that will be printed to. 
	This function will open a file output stream to which it will print a list of edges, by repeatedly calling the visit function.
	A node is printed, followed by the list of its children.

    */
void traverse(string strfname) {
	string ofName = strfname + ".dag";
	ofstream fout;
	fout.open(ofName.c_str(),ios::out);
	DAGedges::iterator it = DAG.begin();
	while(it != DAG.end()) {
		DAGnode PSI = it->first;
		visit(PSI, it->second, 1, fout);
		it++;
		while(it != DAG.end() && it->first == PSI) {
			visit (PSI, it->second, 0, fout);
			it++;
		}
	}
	fout << endl;
	fout.close();
}


//! This is the main function
/*! 
It is mainly taken from the code written by Jim Idle. We only changed the name of the parser and added one line
that calls the traverse function
    
    */
int ANTLR3_CDECL main (int argc, char *argv[])
{
	pANTLR3_UINT8 fName;
	pANTLR3_INPUT_STREAM input;
	plabanLexer lxr;
	pANTLR3_COMMON_TOKEN_STREAM tstream;
	plabanParser psr;

	if (argc < 2 || argv[1] == NULL)
		fName = (pANTLR3_UINT8)"./input";
	else
		fName = (pANTLR3_UINT8)argv[1];

	input = antlr3AsciiFileStreamNew(fName);

	if ( input == NULL) {
		fprintf(stderr, "Failed to open file %s\n", (char *)fName);
		exit(1);
	}

	string strfname = (string)((const char *)fName);

	lxr = labanLexerNew(input);

	if ( lxr == NULL ) {
		fprintf(stderr, "Unable to create the lexer due to malloc() failure1\n");
		exit(1);
	}

	tstream = antlr3CommonTokenStreamSourceNew(ANTLR3_SIZE_HINT, TOKENSOURCE(lxr));

	if (tstream == NULL) {
		fprintf(stderr, "Out of memory trying to allocate token stream\n");
		exit(1);
	}

	psr = labanParserNew(tstream);

	if (psr == NULL) {
		fprintf(stderr, "Out of memory trying to allocate parser\n");
		exit(ANTLR3_ERR_NOMEM);
	}

	psr->decl(psr);

	psr->free(psr);
	psr = NULL;
	tstream->free(tstream);
	tstream = NULL;
	lxr->free(lxr);
	lxr = NULL;
	input->close(input);
	input = NULL;

	traverse(strfname);
	NetworkGraph networkGraph;
	translateToProgGraph(DAG,networkGraph);
	DAGedges DAG2;
	translateFromProgGraph(networkGraph, DAG2);
	//the memory that was allocated in translateToProgGraph should be freed. there is a memory leak now.
	if(DAG == DAG2){
		cout << "Translation check succeeded: translation to ProgGraph and then back to DAGedges yielded the  original graph." << endl;
	}
	else{
		cout << "Translation failed. result from translation and back isn't the same as original graph." << endl;
	}
	string errorMessage;
	bool b = checkConsistency(DAG,errorMessage);
	if(b){
		cout << "Graph is consistent." << endl;
	}
	else {
		cout << "Graph is not consistent" << endl;
		cout << "The following inconsistency was detected:" << endl;
		cout << errorMessage << endl;		
	}

	return 0;
}

